//
// 定义渲染引擎全局的时间工具类，主要用于：帧计算，帧率计算，时间放缩，等功能，同时考虑线程安全和性能优化
//

#pragma once

#include <chrono>
#include <atomic>
#include <array>
#include <algorithm>

namespace EngineUtils {
    class EngineTime final {
    public:

        // 禁止拷贝和赋值构造
        EngineTime(const EngineTime&) = delete;
        EngineTime& operator=(const EngineTime&) = delete;

        // 对外提供静态单例
        static EngineTime& getInstance() noexcept {
            static EngineTime instance;
            return instance;
        }


        // 初始化时间系统
        void Initialize() noexcept {
            m_StartTime = Clock::now();
            m_LastFrameTime = m_StartTime;
            m_CurrentFrameTime = m_StartTime;
        }

        // 更新帧时间（每帧调用一次）
        void tick() noexcept {
            m_LastFrameTime = m_CurrentFrameTime;
            m_CurrentFrameTime = Clock::now();

            // 计算平滑的帧时间
            const auto frameTime = getRawFrameTime();
            m_SmoothFrameTime = calculateSmoothTime(frameTime);

            // 更新帧率统计
            updateFrameRateStats();
        }

        // 获取原始帧时间（秒）：每次drawCall的时间
        [[nodiscard]] float getRawFrameTime() const noexcept {
            return std::chrono::duration<float>(m_CurrentFrameTime - m_LastFrameTime).count();
        }

        // 获取平滑后的帧时间（秒），这里采取平滑的方式计算帧率可以避免噪声的干扰，而且更加贴合人类对于刷新率的感知
        [[nodiscard]] float getSmoothedFrameTime() const noexcept {
            return m_SmoothFrameTime.load(std::memory_order_relaxed);
        }

        // 获取自程序启动以来的时间（秒）
        [[nodiscard]] float getTimeSinceStartup() const noexcept {
            return std::chrono::duration<float>(m_CurrentFrameTime - m_StartTime).count();
        }

        // 获取当前帧率（FPS）
        [[nodiscard]] float getFPS() const noexcept {
            const float smoothedTime = m_SmoothFrameTime.load(std::memory_order_relaxed);
            return smoothedTime > 0.0f ? 1.0f / smoothedTime : 0.0f;
        }

        // 设置时间缩放因子（用于慢动作/快进效果）
        void setTimeScale(float scale) noexcept {
            scale = std::clamp(scale, 0.0f, 10.0f);  // 限制在合理范围内
            m_TimeScale.store(scale, std::memory_order_relaxed);
        }

        // 获取当前时间缩放因子
        [[nodiscard]] float getTimeScale() const noexcept {
            return m_TimeScale.load(std::memory_order_relaxed);
        }

        // 获取缩放后的帧时间
        [[nodiscard]] float getScaledFrameTime() const noexcept {
            return getSmoothedFrameTime() * getTimeScale();
        }

        // 获取当前帧的精确时间点（用于性能分析）
        [[nodiscard]] static std::chrono::high_resolution_clock::time_point Now() noexcept {
            return Clock::now();
        }

        // 获取当前时间
        std::string getNow() noexcept {
            auto now = std::chrono::system_clock::now();
            auto in_time_t = std::chrono::system_clock::to_time_t(now);
            auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

            std::stringstream ss;
            ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S");
            ss << "." << std::setfill('0') << std::setw(3) << ms.count();

            return ss.str();
        }

    private:
        using Clock = std::chrono::high_resolution_clock;          // 高精度时间测量
        using TimePoint = Clock::time_point;                       // 时间点：具体时刻的指针或者引用

        // 私有化构造
        EngineTime() noexcept = default;

        // 平滑计算的帧数
        static constexpr size_t m_FrameTimeHistorySize = 10;       // 计算10帧的历史帧率的平均值

        // 记录特殊时间点
        TimePoint m_StartTime {};                                  // 初始化的时间，可以是程序运行的开始时间或者是第一帧渲染开始前的时间
        TimePoint m_LastFrameTime {};                              // 上一帧的时间点 （通过上一帧的时间和当前帧的时间计算当前这一帧的耗时）
        TimePoint m_CurrentFrameTime {};                           // 当前帧的时间点
        TimePoint m_LastFPSCalculationTime {};                     // 记录的是上一次采样的第一帧的时间（每次采样间隔 = now - m_LastFPSCalculationTime）

        // 帧时间统计
        std::array<float, m_FrameTimeHistorySize> m_FrameTimeHistory = {};
        size_t m_HistoryIndex = 0;
        std::atomic<float> m_SmoothFrameTime { 0.016f };         // 默认其16.7ms，即60Hz
        std::atomic<float> m_TimeScale { 1.0f };

        // 帧率统计
        uint32_t m_FrameCount = 0;                                 // 统计1s内的刷新帧的数量，一般移动端采用1s，PC端采用0.5s的采样间隔，具体视情况而定
        float m_LastFPS = 0.0f;

        // 计算平滑时间(使用移动平均)
        [[nodiscard]] float calculateSmoothTime(float frameTime) noexcept {
            // 使用环形缓冲区存储最近帧时间
            m_FrameTimeHistory[m_HistoryIndex] = frameTime;
            m_HistoryIndex = (m_HistoryIndex + 1) % m_FrameTimeHistorySize;

            // 计算移动平均
            float sum = 0.0f;
            for (float time : m_FrameTimeHistory) {
                sum += time;
            }

            return sum / m_FrameTimeHistorySize;
        }

        // 更新帧率统计
        void updateFrameRateStats() noexcept {
            const auto now = Clock::now();
            const auto elapsed = std::chrono::duration<float>(now - m_LastFPSCalculationTime).count();

            m_FrameCount++;

            // 每秒更新一次FPS统计
            if (elapsed >= 1.0f) {
                m_LastFPS = static_cast<float>(m_FrameCount) / elapsed;
                m_FrameCount = 0;
                m_LastFPSCalculationTime = now;
            }
        }
    };
}

